canvas 图标沿轨迹移动及转向 您所在的位置:网站首页 js 曲线运动 canvas 图标沿轨迹移动及转向

canvas 图标沿轨迹移动及转向

2023-11-12 09:10| 来源: 网络整理| 查看: 265

2021-11-07.gif

本示例代码分为三个主要部分 1. 曲线部分

curve()函数使用贝塞尔曲线实现线条转平滑曲线,贝塞尔曲线转换部分详见 segmentfault.com/a/119000001…

2. 图标移动部分

使用贝塞尔曲线计算公式实现移动效果。

二次贝塞尔曲线公式 (1 - t)^2 * P0 + 2 * t * (1 - t) * P1 + t^2 * P2 三次贝塞尔曲线公式 (1 - t) * (1 - t) * (1 - t) * P0 + 3 * (1 - t) * (1 - t) * t * P1 + 3 * (1 - t) * t * t * P2 + t * t * t * P3 t为0到1 3. 图标转向部分

使用反正切函数实现计算夹角弧度来实现图标的转向。 在开始计算前图标的默认指向角度也要提前了解。如这个手指图标👈默认为180度,正余弦为sin=0 cos=-1夹角弧度为Math.atan2(0, -1)。知道图标的默认弧度后就可实时的计算转向的弧度了。公式为Math.atan2(y2 - y1, x2 - x1) - Math.atan2(0, -1) 在示例代码中有180度和0度的图标弧度计算的参考

DOCTYPE html> Title body { margin: 0; } button{ position: absolute; top: 0; } 开始 let arr = [{"x": 686, "y": 272}, {"x": 686, "y": 271}, {"x": 686, "y": 269}, {"x": 686, "y": 267}, {"x": 686, "y": 265}, {"x": 686, "y": 264}, {"x": 686, "y": 262}, {"x": 686, "y": 260}, {"x": 686, "y": 258}, {"x": 686, "y": 256}, {"x": 685, "y": 253}, {"x": 685, "y": 251}, {"x": 685, "y": 249}, {"x": 685, "y": 247}, {"x": 685, "y": 245}, {"x": 685, "y": 242}, {"x": 685, "y": 241}, {"x": 684, "y": 239}, {"x": 684, "y": 237}, {"x": 683, "y": 234}, {"x": 682, "y": 232}, {"x": 682, "y": 229}, {"x": 682, "y": 228}, {"x": 681, "y": 225}, {"x": 680, "y": 224}, {"x": 679, "y": 221}, {"x": 679, "y": 220}, {"x": 679, "y": 219}, {"x": 678, "y": 217}, {"x": 677, "y": 214}, {"x": 676, "y": 213}, {"x": 675, "y": 211}, {"x": 674, "y": 209}, {"x": 674, "y": 208}, {"x": 672, "y": 207}, {"x": 672, "y": 204}, {"x": 671, "y": 203}, {"x": 669, "y": 201}, {"x": 669, "y": 199}, {"x": 668, "y": 199}, {"x": 668, "y": 198}, {"x": 666, "y": 196}, {"x": 665, "y": 195}, {"x": 665, "y": 193}, {"x": 663, "y": 192}, {"x": 663, "y": 191}, {"x": 661, "y": 189}, {"x": 660, "y": 188}, {"x": 657, "y": 185}, {"x": 656, "y": 183}, {"x": 655, "y": 183}, {"x": 653, "y": 181}, {"x": 652, "y": 180}, {"x": 651, "y": 179}, {"x": 649, "y": 178}, {"x": 648, "y": 176}, {"x": 646, "y": 176}, {"x": 644, "y": 175}, {"x": 643, "y": 174}, {"x": 641, "y": 174}, {"x": 639, "y": 173}, {"x": 637, "y": 172}, {"x": 636, "y": 171}, {"x": 634, "y": 171}, {"x": 633, "y": 171}, {"x": 631, "y": 171}, {"x": 630, "y": 171}, {"x": 628, "y": 171}, {"x": 627, "y": 171}, {"x": 626, "y": 171}, {"x": 624, "y": 170}, {"x": 622, "y": 170}, {"x": 621, "y": 170}, {"x": 619, "y": 170}, {"x": 617, "y": 170}, {"x": 616, "y": 170}, {"x": 615, "y": 170}, {"x": 613, "y": 170}, {"x": 611, "y": 170}, {"x": 610, "y": 170}, {"x": 608, "y": 170}, {"x": 607, "y": 170}, {"x": 604, "y": 170}, {"x": 602, "y": 170}, {"x": 600, "y": 171}, {"x": 599, "y": 171}, {"x": 598, "y": 171}, {"x": 597, "y": 171}, {"x": 596, "y": 171}, {"x": 594, "y": 171}, {"x": 592, "y": 171}, {"x": 591, "y": 172}, {"x": 590, "y": 172}, {"x": 587, "y": 173}, {"x": 584, "y": 173}, {"x": 583, "y": 173}, {"x": 581, "y": 174}, {"x": 580, "y": 175}, {"x": 577, "y": 175}, {"x": 575, "y": 176}, {"x": 573, "y": 178}, {"x": 570, "y": 179}, {"x": 566, "y": 182}, {"x": 563, "y": 184}, {"x": 559, "y": 186}, {"x": 557, "y": 188}, {"x": 554, "y": 191}, {"x": 551, "y": 193}, {"x": 549, "y": 195}, {"x": 547, "y": 197}, {"x": 544, "y": 200}, {"x": 543, "y": 202}, {"x": 541, "y": 204}, {"x": 539, "y": 206}, {"x": 537, "y": 210}, {"x": 534, "y": 213}, {"x": 533, "y": 215}, {"x": 530, "y": 219}, {"x": 529, "y": 221}, {"x": 527, "y": 224}, {"x": 524, "y": 228}, {"x": 523, "y": 230}, {"x": 521, "y": 234}, {"x": 520, "y": 237}, {"x": 518, "y": 241}, {"x": 517, "y": 243}, {"x": 516, "y": 246}, {"x": 516, "y": 248}, {"x": 515, "y": 250}, {"x": 515, "y": 252}, {"x": 514, "y": 255}, {"x": 514, "y": 258}, {"x": 513, "y": 261}, {"x": 513, "y": 265}, {"x": 512, "y": 269}, {"x": 511, "y": 274}, {"x": 509, "y": 278}, {"x": 508, "y": 281}, {"x": 508, "y": 284}, {"x": 507, "y": 293}, {"x": 506, "y": 296}, {"x": 505, "y": 302}, {"x": 504, "y": 308}, {"x": 503, "y": 311}, {"x": 502, "y": 316}, {"x": 501, "y": 322}, {"x": 501, "y": 328}, {"x": 501, "y": 331}, {"x": 500, "y": 337}, {"x": 500, "y": 342}, {"x": 500, "y": 345}, {"x": 500, "y": 349}, {"x": 500, "y": 353}, {"x": 500, "y": 356}, {"x": 500, "y": 359}, {"x": 500, "y": 363}, {"x": 500, "y": 366}, {"x": 500, "y": 369}, {"x": 500, "y": 372}, {"x": 500, "y": 375}, {"x": 500, "y": 380}, {"x": 501, "y": 383}, {"x": 501, "y": 386}, {"x": 501, "y": 390}, {"x": 502, "y": 393}, {"x": 503, "y": 397}, {"x": 503, "y": 400}, {"x": 503, "y": 405}, {"x": 503, "y": 408}, {"x": 504, "y": 411}, {"x": 505, "y": 415}, {"x": 505, "y": 417}, {"x": 506, "y": 419}, {"x": 507, "y": 422}, {"x": 507, "y": 425}, {"x": 508, "y": 427}, {"x": 509, "y": 430}, {"x": 510, "y": 432}, {"x": 510, "y": 435}, {"x": 511, "y": 438}, {"x": 511, "y": 440}, {"x": 512, "y": 443}, {"x": 513, "y": 447}, {"x": 513, "y": 449}, {"x": 514, "y": 453}, {"x": 515, "y": 455}, {"x": 516, "y": 457}, {"x": 516, "y": 460}, {"x": 517, "y": 462}, {"x": 518, "y": 463}, {"x": 519, "y": 465}, {"x": 519, "y": 467}, {"x": 521, "y": 469}, {"x": 521, "y": 470}, {"x": 522, "y": 473}, {"x": 524, "y": 476}, {"x": 525, "y": 478}, {"x": 526, "y": 480}, {"x": 527, "y": 482}, {"x": 529, "y": 484}, {"x": 530, "y": 485}, {"x": 531, "y": 486}, {"x": 532, "y": 488}, {"x": 533, "y": 489}, {"x": 535, "y": 491}, {"x": 537, "y": 494}, {"x": 538, "y": 495}, {"x": 541, "y": 497}, {"x": 541, "y": 498}, {"x": 544, "y": 500}, {"x": 546, "y": 502}, {"x": 548, "y": 504}, {"x": 550, "y": 506}, {"x": 552, "y": 507}, {"x": 554, "y": 509}, {"x": 556, "y": 511}, {"x": 559, "y": 513}, {"x": 561, "y": 515}, {"x": 562, "y": 516}, {"x": 565, "y": 518}, {"x": 566, "y": 518}, {"x": 568, "y": 520}, {"x": 570, "y": 521}, {"x": 574, "y": 524}, {"x": 576, "y": 525}, {"x": 578, "y": 526}, {"x": 580, "y": 527}, {"x": 582, "y": 528}, {"x": 583, "y": 528}, {"x": 584, "y": 529}, {"x": 586, "y": 529}, {"x": 587, "y": 530}, {"x": 589, "y": 530}, {"x": 591, "y": 531}, {"x": 592, "y": 532}, {"x": 594, "y": 532}, {"x": 596, "y": 532}, {"x": 597, "y": 533}, {"x": 599, "y": 533}, {"x": 600, "y": 534}, {"x": 602, "y": 534}, {"x": 603, "y": 534}, {"x": 604, "y": 534}, {"x": 606, "y": 534}, {"x": 608, "y": 534}, {"x": 609, "y": 534}, {"x": 610, "y": 534}, {"x": 611, "y": 534}, {"x": 612, "y": 534}, {"x": 613, "y": 534}, {"x": 615, "y": 533}, {"x": 618, "y": 533}, {"x": 619, "y": 532}, {"x": 621, "y": 531}, {"x": 623, "y": 530}, {"x": 626, "y": 529}, {"x": 627, "y": 528}, {"x": 628, "y": 526}, {"x": 630, "y": 525}, {"x": 632, "y": 523}, {"x": 635, "y": 521}, {"x": 639, "y": 518}, {"x": 641, "y": 517}, {"x": 643, "y": 515}, {"x": 644, "y": 515}, {"x": 646, "y": 513}, {"x": 647, "y": 512}, {"x": 649, "y": 510}, {"x": 649, "y": 509}, {"x": 651, "y": 508}, {"x": 652, "y": 505}, {"x": 654, "y": 503}, {"x": 655, "y": 501}, {"x": 657, "y": 500}, {"x": 657, "y": 497}, {"x": 659, "y": 495}, {"x": 660, "y": 494}, {"x": 660, "y": 492}, {"x": 662, "y": 490}, {"x": 662, "y": 488}, {"x": 663, "y": 487}, {"x": 665, "y": 484}, {"x": 665, "y": 482}, {"x": 666, "y": 480}, {"x": 667, "y": 478}, {"x": 668, "y": 476}, {"x": 668, "y": 473}, {"x": 669, "y": 470}, {"x": 670, "y": 468}, {"x": 671, "y": 466}, {"x": 671, "y": 463}, {"x": 671, "y": 461}, {"x": 672, "y": 458}, {"x": 672, "y": 455}, {"x": 673, "y": 453}, {"x": 673, "y": 451}, {"x": 674, "y": 448}, {"x": 674, "y": 446}, {"x": 674, "y": 444}, {"x": 674, "y": 441}, {"x": 674, "y": 439}, {"x": 675, "y": 436}, {"x": 675, "y": 431}, {"x": 676, "y": 429}, {"x": 676, "y": 427}, {"x": 676, "y": 425}, {"x": 676, "y": 423}, {"x": 676, "y": 421}, {"x": 677, "y": 419}, {"x": 677, "y": 417}, {"x": 678, "y": 416}, {"x": 678, "y": 414}, {"x": 678, "y": 412}, {"x": 679, "y": 411}, {"x": 679, "y": 410}, {"x": 679, "y": 409}, {"x": 679, "y": 407}, {"x": 679, "y": 405}, {"x": 680, "y": 405}, {"x": 680, "y": 404}, {"x": 680, "y": 403}, {"x": 680, "y": 402}, {"x": 680, "y": 401}, {"x": 680, "y": 400}, {"x": 680, "y": 399}, {"x": 680, "y": 398}, {"x": 680, "y": 397}, {"x": 680, "y": 396}, {"x": 680, "y": 395}, {"x": 680, "y": 395}] // [{"x": 151, "y": 54}, {"x": 150, "y": 57}, {"x": 149, "y": 63}, {"x": 147, "y": 74}, {"x": 144, "y": 89}, {"x": 142, "y": 99}, {"x": 141, "y": 110}, {"x": 138, "y": 134}, {"x": 138, "y": 159}, {"x": 138, "y": 175}, {"x": 140, "y": 217}, {"x": 149, "y": 254}, {"x": 160, "y": 295}, {"x": 170, "y": 318}, {"x": 191, "y": 365}, {"x": 212, "y": 402}, {"x": 224, "y": 426}, {"x": 237, "y": 443}, {"x": 242, "y": 449}, {"x": 254, "y": 464}, {"x": 260, "y": 470}, {"x": 263, "y": 473}, {"x": 268, "y": 478}, {"x": 273, "y": 482}, {"x": 277, "y": 485}, {"x": 280, "y": 488}, {"x": 285, "y": 492}, {"x": 287, "y": 494}, {"x": 293, "y": 500}, {"x": 296, "y": 504}, {"x": 300, "y": 507}, {"x": 302, "y": 510}, {"x": 306, "y": 513}, {"x": 306, "y": 514}, {"x": 307, "y": 515}, {"x": 307, "y": 515}] // [{"x": 318, "y": 111}, {"x": 317, "y": 113}, {"x": 315, "y": 116}, {"x": 313, "y": 121}, {"x": 309, "y": 127}, {"x": 306, "y": 133}, {"x": 301, "y": 140}, {"x": 296, "y": 149}, {"x": 293, "y": 156}, {"x": 286, "y": 171}, {"x": 278, "y": 186}, {"x": 268, "y": 204}, {"x": 261, "y": 220}, {"x": 252, "y": 237}, {"x": 248, "y": 248}, {"x": 242, "y": 263}, {"x": 235, "y": 280}, {"x": 230, "y": 299}, {"x": 226, "y": 315}, {"x": 225, "y": 326}, {"x": 224, "y": 336}, {"x": 224, "y": 353}, {"x": 227, "y": 369}, {"x": 231, "y": 381}, {"x": 237, "y": 393}, {"x": 244, "y": 408}, {"x": 250, "y": 415}, {"x": 263, "y": 427}, {"x": 275, "y": 438}, {"x": 289, "y": 449}, {"x": 303, "y": 457}, {"x": 331, "y": 473}, {"x": 346, "y": 479}, {"x": 379, "y": 489}, {"x": 398, "y": 493}, {"x": 426, "y": 498}, {"x": 457, "y": 501}, {"x": 474, "y": 501}, {"x": 501, "y": 501}, {"x": 519, "y": 500}, {"x": 533, "y": 495}, {"x": 550, "y": 490}, {"x": 563, "y": 481}, {"x": 570, "y": 476}, {"x": 579, "y": 464}, {"x": 584, "y": 455}, {"x": 588, "y": 444}, {"x": 589, "y": 434}, {"x": 589, "y": 421}, {"x": 589, "y": 409}, {"x": 585, "y": 391}, {"x": 579, "y": 375}, {"x": 572, "y": 359}, {"x": 561, "y": 336}, {"x": 545, "y": 314}, {"x": 538, "y": 306}, {"x": 517, "y": 282}, {"x": 504, "y": 271}, {"x": 485, "y": 257}, {"x": 469, "y": 246}, {"x": 455, "y": 238}, {"x": 441, "y": 232}, {"x": 423, "y": 223}, {"x": 409, "y": 219}, {"x": 392, "y": 214}, {"x": 376, "y": 210}, {"x": 367, "y": 209}, {"x": 353, "y": 208}, {"x": 345, "y": 208}, {"x": 332, "y": 208}, {"x": 317, "y": 208}, {"x": 308, "y": 208}, {"x": 298, "y": 210}, {"x": 292, "y": 211}, {"x": 282, "y": 214}, {"x": 271, "y": 217}, {"x": 260, "y": 221}, {"x": 253, "y": 223}, {"x": 241, "y": 227}, {"x": 231, "y": 230}, {"x": 223, "y": 234}, {"x": 217, "y": 237}, {"x": 208, "y": 240}, {"x": 204, "y": 241}, {"x": 198, "y": 244}, {"x": 192, "y": 247}, {"x": 190, "y": 249}, {"x": 184, "y": 252}, {"x": 181, "y": 253}, {"x": 174, "y": 257}, {"x": 169, "y": 260}, {"x": 166, "y": 262}, {"x": 162, "y": 265}, {"x": 161, "y": 266}, {"x": 159, "y": 268}, {"x": 157, "y": 269}, {"x": 156, "y": 270}, {"x": 156, "y": 270}] let canvas = document.querySelector('canvas') let ctx = canvas.getContext('2d') let i = 0 let count = 0 let len = arr.length let xy = [] let old = [] let now, elapsed; let fpsInterval = 1000 / 15; // 动画帧数设置 let then = Date.now(); curve() arrow(arr[0].x, arr[0].y) function frame() { // 控制帧数 now = Date.now(); elapsed = now - then; if (elapsed > fpsInterval) { then = now - (elapsed % fpsInterval); if (!arr[count + 2]) { return cancelAnimationFrame(frame) } else { ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); curve() // 贝塞尔曲线运动 xy = quadraticBezierCurve(i / len, arr[count], arr[count + 1], arr[count + 2]) arrow(xy[0], xy[1]) // 记录坐标 old = [xy[0], xy[1]] i++ count += 2 } } return requestAnimationFrame(frame) } /** * 贝塞尔曲线 **/ function curve() { let endPoint = null let beginPoint = arr[0] ctx.beginPath() arr.map((item, index) => { if (arr[index + 1]) { endPoint = { x: (item.x + arr[index + 1].x) / 2, y: (item.y + arr[index + 1].y) / 2, } } else { endPoint = item; } ctx.moveTo(beginPoint.x, beginPoint.y); ctx.quadraticCurveTo(item.x, item.y, endPoint.x, endPoint.y); beginPoint = endPoint; }) ctx.stroke() } /** * 箭头 * 标志(👈👉)朝向:Math.atan2(0, 1) 0度朝向 , Math.atan2(0, -1) 180度朝向 * 必须要减去标志的朝向弧度 **/ function arrow(x, y) { ctx.save(); // 修改原点 ctx.translate(x, y) // 旋转 if (old.length) { ctx.rotate(Math.atan2(y - old[1], x - old[0]) - Math.atan2(0, -1)) } else { ctx.rotate(Math.atan2(arr[1].y - y, arr[1].x - x) - Math.atan2(0, -1)) } // 改变回中心点 ctx.translate(-x - 20, -y + 10) ctx.font = "30px Arial"; ctx.fillText("👈", x, y); // ctx.fillText("👉", x, y ); ctx.restore(); } /** * 直线转贝塞尔曲线 **/ function quadraticBezierCurve(t, p1, cp, p2) { let x = (1 - t) * (1 - t) * p1.x + 2 * t * (1 - t) * cp.x + t * t * p2.x; let y = (1 - t) * (1 - t) * p1.y + 2 * t * (1 - t) * cp.y + t * t * p2.y; return [x, y]; }


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有